use clap::Parser;
use ssh2::Session;
use std::{io::Read, net::TcpStream, process::exit};

#[derive(Parser, Clone, Debug)]
struct Opt {
    /// Unix SSH Host
    #[arg(short = 'H', long, env = "SSH_CLI_HOST")]
    host: String,

    /// Unix SSH Username
    #[arg(short, long, env = "SSH_CLI_USER")]
    username: String,

    /// Unix SSH User Password
    #[arg(short, long, env = "SSH_CLI_PASSWORD")]
    password: String,

    /// Unix SSH Port
    #[arg(short = 'P', long, default_value="22")]
    port: String,

    /// Only supports a single command
    #[arg(short, long, env = "SSH_CLI_COMMAND")]
    test_cmd: String,
}

fn main() {
    let opt = Opt::parse();

    // Connect to the local SSH server
    let tcp = TcpStream::connect(format!("{}:{}", opt.host, opt.port)).unwrap();
    let mut sess = Session::new().unwrap();
    sess.set_tcp_stream(tcp);
    sess.handshake().unwrap();

    sess.userauth_password(&opt.username, &opt.password)
        .unwrap();
    assert!(sess.authenticated());

    let mut channel = sess.channel_session().unwrap();
    channel.exec(&opt.test_cmd).unwrap();

    let mut stdout = String::new();
    channel.read_to_string(&mut stdout).unwrap();
    let mut stderr: String = String::new();
    channel.stderr().read_to_string(&mut stderr).unwrap();

    channel.wait_close().unwrap();
    let status = channel.exit_status().unwrap();

    println!("info1: cmd: `{}`", &opt.test_cmd);
    println!("info2: stdout: {}", stdout.trim_end_matches("\n"));
    println!("info3: stderr: {}", stderr);
    println!("info4: exit code: {}", status);
    exit(status);
}
